from rest_framework import serializers

from luffy_city.settings import constants
from .models import Order, OrderDetail
from datetime import datetime
import random
from django.db import transaction
from django_redis import get_redis_connection
from courses.models import Course, CourseExpire
from coupon.models import UserCoupon, Coupon


class OrderModelSerializer(serializers.ModelSerializer):
    """订单的序列化器"""

    class Meta:
        model = Order
        fields = ['order_number', 'pay_type', 'credit', 'coupon']
        read_only_fields = ['order_number']
        extra_kwargs = {
            'pay_type': {'write_only': True, 'required': True},
            'credit': {'write_only': True},
            'coupon': {'write_only': True},
        }

    def validate(self, attrs):
        # todo 校验是否使用了积分

        # todo 校验是否使用了优惠券，优惠券是否在有效期内
        user_coupon_id = attrs.get('coupon')

        if user_coupon_id > 0:
            now = datetime.now()
            try:
                usercoupon = UserCoupon.objects.get(pk=user_coupon_id, start_time__lte=now)
                if now.timestamp() > usercoupon.end_time.timestamp():
                    raise serializers.ValidationError('优惠券没有在正常使用范围内！已经过期，或者没有到达使用时间')
            except:
                raise serializers.ValidationError('优惠券使用错误')

        return attrs

    def create(self, validated_data):
        """保存订单"""

        # 生成订单号   = 年月日时分秒+用户id+随机数

        # 在序列化器中，如果要获取视图中的数据可以通过 self.context['request],  self.context['view'] 获取用户ID
        user = self.context['request'].user
        order_number = datetime.now().strftime('%Y%m%d%H%M%S') + ('%06d' % user.id) + ("%04d" % random.randint(0, 9999))

        with transaction.atomic():  # 开启事务的自动提交
            # 设置回滚点
            save_id = transaction.savepoint()
            # 1.生成订单
            try:
                coupon = validated_data.get('coupon')
                credit = validated_data.get('credit')
                order = Order.objects.create(
                    order_title="路飞学诚课程购买",
                    total_price=0,
                    real_price=0,
                    order_number=order_number,
                    pay_type=validated_data.get('pay_type'),
                    credit=credit,
                    coupon=coupon,
                    user_id=user.id

                )
                # 2.连接redis
                redis_conn = get_redis_connection('cart')

                # 3.到redis中提取对一个用户的购物车
                cart_hash = redis_conn.hgetall("cart_%s" % user.id)
                selected_set = redis_conn.smembers("selected_%s" % user.id)

                if selected_set is None:
                    transaction.savepoint_rollback(save_id)
                    return serializers.ValidationError('对不起，购物车中未勾选该商品')

                # 4.提取购物车中勾选的商品信息
                total_price = 0
                pipe = redis_conn.pipeline()
                pipe.multi()
                for course_id_bytes in selected_set:
                    course_id = course_id_bytes.decode()
                    expire = int(cart_hash[course_id_bytes].decode())

                    try:
                        course = Course.objects.get(pk=course_id, is_show=True, is_delete=False)
                    except Course.DoesNotExist:
                        # 如果商品被下架或者被删除则不显示到购物车中
                        continue

                    try:
                        ret = CourseExpire.objects.get(course_id=course_id, expire=expire)
                        expire = ret.expire
                    except:
                        expire = 0

                    # 5.保存商品到订单详情中
                    real_price = course.get_discount_pirce_by_expire(expire)
                    OrderDetail.objects.create(
                        order=order,
                        course=course,
                        expire=expire,
                        price=course.get_price_by_expire(expire),
                        real_price=real_price,
                        discount_name=course.discount_name
                    )

                    # 6.从redis中删除对应已经添加到订单里面说的商品
                    pipe.hdel('cart_%s' % user.id, course_id)
                    pipe.srem("selected_%s" % user.id, course_id)

                    # 计算商品总价
                    total_price += float(real_price)

                    # 执行redis的事务管道
                pipe.execute()

                # 判断客户端如果使用了优惠券，则计算优惠券的折扣价格
                if coupon > 0:
                    # 客户端使用了优惠券
                    usercoupon = UserCoupon.objects.get(pk=coupon)
                    if total_price < usercoupon.coupon.condition:
                        transaction.savepoint_rollback(save_id)
                        serializers.ValidationError('没有达到该优惠券的使用条件')

                    # 计算优惠券的抵扣价格
                    sale = float(usercoupon.coupon.sale[1:])
                    if usercoupon.coupon.coupon_type == 1:
                        """减免优惠券"""
                        coupon_price = sale
                    else:
                        """折扣优惠券"""
                        coupon_price = total_price * (1 - sale)

                    # 下单以后，如果使用了优惠券，则改变当前优惠券的状态
                    # 将来如果用户对于当前订单进行了取消，或者订单超时取消，则还原当前优惠券的状态
                    usercoupon.is_use = True
                    usercoupon.save()

                credit_price = 0
                # if credit > 0:
                #     """使用了积分"""
                #     if (total_price - coupon_price) * constants.RMB_CREDIT < credit:
                #         """如果积分使用数额超过订单能兑换的最大数额，就有问题"""
                #         transaction.savepoint_rollback(save_id)
                #         raise serializers.ValidationError("生成订单失败!")
                #
                #     # 扣除积分
                #     credit_price = credit / constants.RMB_CREDIT
                #     user.credit -= credit
                #     user.save()

                # 更新订单总价
                order.total_price = total_price  # 订单总价，不涉及积分和优惠券的抵扣
                order.real_price = float("%.2f" % (total_price - coupon_price - credit_price))  # 订单实付价，在订单总价的基础上，扣除积分和优惠券
                order.save()

            except:
                transaction.savepoint_rollback(save_id)
                raise serializers.ValidationError('生成订单失败！')

        # 返回订单的生成结果
        return order

